/**
 * @file gn_os_adapter_system.c
 * @brief 操作系统相关接口
 * @author yejing (yejh@gongniu.cn)
 * @version 1.0
 * @date 2021-07-08
 * 
 * Copyright 2021-2023 GongNiu Inc. All Rights Reserved.
 * 
 */

#include "freertos/FreeRTOS.h"
#include "esp_system.h"

#include "bull_hal_adapter.h"
#include "bull_hal_sys_system.h"



/***********************************************************
*************************variable define********************
***********************************************************/


/**
 * @brief bull_hal_sys_sleep用于系统sleep
 * 
 * @param[in] msTime sleep time is ms
 */
void bull_hal_sys_sleep( uint32_t msTime )
{
    vTaskDelay((msTime)/(portTICK_RATE_MS));
}


/**
 * @brief 得到系统剩余内存
 * 
 * @return uint32_t 
 */
uint32_t bull_hal_sys_get_free_heap_size(void)
{
    return esp_get_free_heap_size();
}

/**
 * @brief 获取得到内部剩余内存
 * 
 * @return uint32_t 
 */
// uint32_t bull_hal_sys_get_free_internal_heap_size( void )
// {
//     return esp_get_free_internal_heap_size();
// }
uint32_t bull_hal_sys_get_free_total_heap_size( void )
{
    return esp_get_free_heap_size();
}


uint32_t bull_hal_sys_get_free_internal_heap_size( void )
{
    return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
}

uint32_t bull_hal_sys_get_free_internal_8bit_heap_size( void )
{
    return heap_caps_get_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
}

uint32_t bull_hal_sys_get_free_largest_heap_size( void )
{
    return heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
}

uint32_t bull_hal_sys_get_free_internal_minimum_heap_size( void )
{
    return heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
}


/**
 * @brief bull_hal_sys_get_tickcount 
 * @return SYS_TICK_T 
 */
uint32_t bull_hal_sys_get_tickcount(void)
{
    return (uint32_t)xTaskGetTickCount();
}


/**
 * @brief bull_hal_sys_get_tickratems用于获取系统ticket是多少个ms
 * 
 * @return the time is ms of a system ticket
 */
uint32_t bull_hal_sys_get_tickratems(void)
{
    return (unsigned int)portTICK_RATE_MS;
}


/**
 * @brief bull_hal_sys_is_in_isr 用于检查系统是否处于中断上下文
 * 
 * @return true 
 * @return false 
 */
bool bull_hal_sys_is_in_isr(void)
{
    if(0 != xPortInIsrContext()) {
        return TRUE;
    }

    return FALSE;
}


/**
 * @brief bull_hal_sys_restart 用于重启系统
 * 
 */
void bull_hal_sys_restart(void)
{
    esp_restart();
}


/**
 * @brief bull_hal_sys_get_min_heap_size/最小剩余内存大小
 * 
 * @return int <0: don't support  >=0: mini heap size/free memory
 */
int bull_hal_sys_get_min_free_heap_size(void)
{
	return (int)xPortGetMinimumEverFreeHeapSize();
}


/**
 * @brief bull_hal_sys_get_reset_reason 用于获取硬件重启原因
 * 
 * @return 硬件重启原因
 */
BULL_RST_REASON_E bull_hal_sys_get_reset_reason(void)
{
	esp_reset_reason_t esp_reason = esp_reset_reason();

    BULL_RST_REASON_E bull_reason = BULL_RST_UNSUPPORT;

    switch (esp_reason)
    {
        case ESP_RST_POWERON:
            bull_reason = BULL_RST_POWER_ON;
            break;

        case ESP_RST_SW:
            bull_reason = BULL_RST_SOFTWARE;
            break;

        case ESP_RST_WDT:
            bull_reason = BULL_RST_SOFTWARE_WATCHDOG;
            break;

        default:
            bull_reason = esp_reason;
            break;
    }

    return bull_reason;
}



/**
 * @brief gn_os_adapt_get_random_data用于获取指定条件下的随机数
 * 
 * @param[in] range 
 * @return 随机数
 */
uint32_t  bull_hal_sys_get_random_data( IN uint32_t range)
{
    uint32_t val = esp_random();
    return (val % range);
}



/**
 * @brief 获取系统时间(输出结构体)
 * 
 * @return int 
 */
int bull_hal_sys_get_time( OUT BULL_TM_S *tm )
{
    BULL_TM_S t_time = {0};
    time_t  time_now = 0;

    time(&time_now);
    localtime_r(&time_now, &t_time);

    tm->tm_year= t_time.tm_year;
    tm->tm_mon = t_time.tm_mon;
    tm->tm_mday= t_time.tm_mday;
    tm->tm_hour= t_time.tm_hour;
    tm->tm_min = t_time.tm_min;
    tm->tm_sec = t_time.tm_sec;
    tm->tm_wday = t_time.tm_wday;

    return OPRT_OS_ADAPTER_OK;
}

/**
 * @brief 获取系统时间 (输出字符串)
 * 
 * @return int 
 */
int bull_hal_sys_get_time_char( OUT char * nowtime )
{
    time_t  now;
    BULL_TM_S timeinfo;
    
    time(&now);
    localtime_r(&now, &timeinfo);
 
    sprintf( nowtime,"%02d-%02d-%02d %02d:%02d:%02d",timeinfo.tm_year+1900,timeinfo.tm_mon+1,timeinfo.tm_mday,timeinfo.tm_hour,timeinfo.tm_min,timeinfo.tm_sec);

    return OPRT_OS_ADAPTER_OK;
}


/**
 * @brief 获取当前时间戳
 * 
 * @return TIME_T 
 */
time_t  bull_hal_get_now_timestamp( void )
{
    time_t  now;
    BULL_TM_S timeinfo;
    
    time(&now);
    localtime_r(&now, &timeinfo);

    return mktime( &timeinfo );
}

/**
 * @brief 基于输入时间获取时间戳
 * 
 * @param timeinfo 
 * @return TIME_T 
 */
time_t  bull_hal_get_timestamp_base_time( BULL_TM_S timeinfo )
{
    return mktime( &timeinfo );
}

/**
 * @brief 设置系统时间
 * 
 * @param daya 
 * @param hour 
 * @param min 
 * @param sec 
 */
void bull_hal_set_sys_time( int daya, int hour, int min, int sec )
{
    BULL_TM_S sys_time ={ 0 };
    bull_hal_sys_get_time( &sys_time );
    sys_time.tm_mday = daya;
    sys_time.tm_hour = hour;
    sys_time.tm_min = min;
    sys_time.tm_sec = sec;

    time_t time = mktime(&sys_time);

    struct timeval tv = {
        .tv_sec = time,
        .tv_usec = 0,
    };
    
    settimeofday( &tv, NULL );
}

